home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DTP / DTP_TEX / H220.ZIP / ITRNS211.ZIP / SRC / ICHAR.C < prev    next >
C/C++ Source or Header  |  1991-10-13  |  15KB  |  464 lines

  1. /*
  2.  *========================================================================== 
  3.  * Copyright 1991 Avinash Chopde, All Rights Reserved.
  4.  *
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both that
  8.  * copyright notice and this permission notice appear in supporting
  9.  * documentation, and that the name of Avinash Chopde not be used in
  10.  * advertising or publicity pertaining to distribution of the software
  11.  * without specific, written prior permission.
  12.  * Avinash Chopde makes no representations about the suitability of this
  13.  * software for any purpose.
  14.  * It is provided "as is" without express or implied warranty.
  15.  *
  16.  * AVINASH CHOPDE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  17.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  18.  * IN NO EVENT SHALL AVINASH CHOPDE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  19.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  22.  * OF THIS SOFTWARE.
  23.  *
  24.  * Author:  Avinash Chopde, 1991
  25.  *        C2 Colonial Drive #4, Andover, MA 01810, USA.
  26.  *
  27.  */
  28.  
  29. #include "itrans.h"
  30.  
  31. static char S_RCSID[] = "$Header: e:/itrans/src/rcs/ichar.c 1.4 91/10/13 16:49:34 avinash Exp $";
  32.  
  33. /* =================================================================== */
  34. static int S_get_cus_form(font_t* fptr, /* the font data structure to use */
  35.         letter_t dlet, /* letter searched for */
  36.         comp_unit_t** cus, /* will return a pointer to the cus here */
  37.         comp_unit_t** imp, /* will return implicit char creation ptr */
  38.         int* lastform,
  39.         int* lastlig); /* whether last two cons have a ligature */
  40. static int S_add_cus(pschar_t psfm[], comp_unit_t* pcu, comp_unit_t cu);
  41. /* =================================================================== */
  42. /* Handle a letter (possibly complex) */
  43.  
  44. /******
  45.         (font_t* fptr, the font data structure to use
  46.         letter_t dlet, letter to convert 
  47.         comp_unit_t pcus[], the comp units that make this
  48.                     letter - all u_pschar are valid
  49.                     PostScript codes, or NO_PSCHAR
  50.                     
  51.         int    size_pcus, array size of ecus- number of elements 
  52.         int *ox, int *oy, the orgin of this letter 
  53.         int *width) the width of this complete letter 
  54. ********/
  55. int make_letter(font_t* fptr,
  56.         letter_t dlet,
  57.         comp_unit_t pcus[],
  58.         int    size_pcus,
  59.         int *ox, int *oy,
  60.         int *width)
  61. {
  62.     int num_pcus; /* number of postscript chars that were added to pcus */
  63.     int pcode;
  64.     comp_unit_t*    lcus;  /* comp units that make the form of
  65.                 * the given letter dlet
  66.                 */
  67.     comp_unit_t*    icus;  /* comp units that make the implicit form
  68.                 * of the given letter dlet
  69.                 */
  70.     comp_unit_t*    startcus;
  71.     letter_t    rcons; /* for recursive calls */
  72.     int x1, y1, w, i, j, c1, c2, lastform, nolig, lastlig;
  73.  
  74.     num_pcus = 0;
  75.     *ox = *oy = 0;
  76.     *width = 0;
  77.     x1 = y1  = w = 0;
  78.  
  79. #ifdef DEBUG
  80. fprintf(stderr, "in make_letter\n");
  81. #endif
  82.     if (!S_get_cus_form(fptr, dlet, &lcus, &icus, &lastform, &lastlig)) {
  83.         /* some error, illegal char, incomplete fptr
  84.          * data structure, etc
  85.          */
  86.     return 0; /* 0 elements added */
  87.     }
  88.  
  89.     /* collect all the PS chars in lcus into the output array */
  90.     while (lcus) {
  91.  
  92.         /* get the PS code of this unit */
  93.     pcode = lcus->u_pschar;
  94.  
  95. #ifdef DEBUG
  96. fprintf(stderr, "while lcus in make_letter: pcode is %d\n", pcode);
  97. #endif /*DEBUG*/
  98.     if (pcode == NO_PSCHAR || (pcode >= 0 && pcode <= 255)) {
  99.         /* valid PostScript code */
  100.  
  101.         num_pcus += S_add_cus(fptr->psfm, &pcus[num_pcus], *lcus);
  102.  
  103.         /* update origin and width */
  104.         /* XXX need to track bounding boxes etc */
  105.  
  106.     } else if (pcode == IMPLICIT_PSCHAR && icus) {
  107.         /* Need to use the implicit char description, and have a
  108.          * valid pointer to comp_units that compose the implicit
  109.          * char.
  110.          */
  111.         startcus = icus;
  112.         while (startcus) {
  113.  
  114. #ifdef DEBUG
  115. fprintf(stderr, "while startcus in make_letter: pcode is %d\n", pcus[num_pcus-1].u_pschar);
  116. #endif /*DEBUG*/
  117.  
  118.             /* error check */
  119.             if ( startcus->u_pschar != NO_PSCHAR &&
  120.             (startcus->u_pschar < 0 || startcus->u_pschar > 255)) {
  121.  
  122.             fprintf(stderr, "ERROR: %d illegal pschar in implicit comp units\n", startcus->u_pschar);
  123.             } else {
  124.             num_pcus += S_add_cus(fptr->psfm,&pcus[num_pcus],*startcus);
  125.         }
  126.  
  127.         startcus = startcus->next;
  128.         }
  129.  
  130.  
  131.     } else if (pcode == IMPLICIT_PSCHAR) {
  132.         /* implies that no implicit char defined for this letter, and
  133.          * the letter is complex, and has to be split into
  134.          * simpler parts
  135.          * The way it is done is that every consonant is
  136.          * printed out in HALF_FORM, except the last
  137.          * consonant, which is printed out in its IMPLICIT_FORM.
  138.          ************
  139.          * What to do here is driven by the CONSONANTS_MANY case
  140.          * in S_get_cus_root()
  141.          * Of course, be careful, this could also be CONS..DOUBLE...
  142.          * in case the IFM file contains SAME_AS CCS statements
  143.          * but no implicit char defns...
  144.          */
  145. #ifdef DEBUG
  146. fprintf(stderr, "make_letter: pcode IMPLICIT, no icus, looping for halfforms\n");
  147. #endif /*DEBUG*/
  148.  
  149.         for (i = 0; i < dlet.n; i ++) {
  150.  
  151. #ifdef DEBUG
  152. fprintf(stderr, "make-letter i %d dlet.n %d lastlig %d\n", i, dlet.n, lastlig);
  153. #endif
  154.         /* check if a ligature has been defined for
  155.          * (current char, next char) pair, use it if available
  156.          */
  157.         if (i < (dlet.n-1)) { /* i.e, two more consonants left..*/
  158.  
  159.             c1 = _I_(dlet.cons[i]); c2 = _I_(dlet.cons[i+1]);
  160.             if (i == (dlet.n-1)) j = lastform; /* last chars */
  161.             else j = HALF_FORM; /* still more to come,so use halfform*/
  162.             nolig = ((dlet.nolig[i]) || (lastlig && i == (dlet.n-3)));
  163. #ifdef DEBUG
  164. fprintf(stderr, "makeletter nolig %d\n", nolig);
  165. #endif
  166.             /* if last lig exists, do not use the 
  167.              * secondlast consonant with the thirdlast consonant.
  168.              * -- just display the thirdlast consonant in
  169.              * half form.
  170.              */
  171.             if (!nolig && fptr->ligatures[c1][c2].cus &&
  172.                     fptr->ligatures[c1][c2].cus[IMPLICIT_FORM]) {
  173.                 /* just check for existence of the IMPLICIT_FORM-
  174.                  * if it exists, the half-form will also
  175.                  * exist---other way around is not true!.
  176.                  */
  177. #ifdef DEBUG
  178.             fprintf(stderr, "C1: %d, C2 %d, cus(%d)\n", c1, c2,
  179.                     fptr->ligatures[c1][c2].cus[j]);
  180. #endif /*DEBUG*/
  181.             /* found ligature! */
  182.                 if (i == (dlet.n-2)) j = lastform; /* last chars */
  183.                 else j = HALF_FORM; /* more to come,so use halfform*/
  184.             rcons.n = 2; rcons.v = j;
  185.             rcons.type = CONSONANT_DOUBLE_TYPE;
  186.             rcons.cons[0] = dlet.cons[i];
  187.             rcons.cons[1] = dlet.cons[i+1];
  188.             rcons.nolig[0] = FALSE;
  189.             i++; /* have used up next char too */
  190.             } else {
  191.             /* no ligature defined, draw a half form */
  192.             rcons.n = 1; rcons.v = HALF_FORM;
  193.             rcons.type = CONSONANT_SINGLE_TYPE;
  194.             rcons.cons[0] = dlet.cons[i];
  195.             }
  196.         } else { /* this is the last char */
  197.             rcons.n = 1; rcons.v = lastform;
  198.             rcons.type = CONSONANT_SINGLE_TYPE;
  199.             rcons.cons[0] = dlet.cons[i];
  200.         }
  201.  
  202.         j = make_letter(fptr, rcons, &pcus[num_pcus],
  203.                 size_pcus - num_pcus, &x1, &y1, &w);
  204.         /* recompute origin, width */
  205.         num_pcus += j;
  206.         }
  207.     } else { /* ERROR */
  208.         fprintf(stderr, "ERROR ERROR: %d illegal pschar in Form comp units\n", pcode);
  209.     }
  210.  
  211.  
  212.     lcus = lcus->next;
  213.     } /* while (lcus) */
  214.  
  215. #ifdef DEBUG
  216. fprintf(stderr, "make_letter::created CUS containging %d cus\n", num_pcus);
  217. #endif /*DEBUG*/
  218.  
  219.     /* keep the next pointers in the pcus correct */
  220.     for (i = 0; i < num_pcus; i ++) {
  221.     pcus[i].next = &pcus[i+1];
  222.     }
  223.     if (num_pcus > 0) pcus[num_pcus-1].next = NULL;
  224.  
  225.     return num_pcus;
  226.  
  227. } /* make_letter() */
  228. /* =================================================================== */
  229. static comp_unit_t S_implicit_cu = {IMPLICIT_PSCHAR, 0, 0, 0, NULL};
  230.  
  231. static int S_get_cus_form(font_t* fptr, /* the font data structure to use */
  232.         letter_t dlet, /* letter searched for */
  233.         comp_unit_t** cus, /* will return a pointer to the cus here */
  234.         comp_unit_t** imp, /* will return implicit char creation ptr */
  235.         int*    lastform,
  236.         int*    lastlig)
  237.             /* lastform: CONSDOUBLE/MANY return form to use
  238.                    * of the last consonant (usually
  239.                    * IMPLICIT_FORM)
  240.                    */
  241.             /* lastlig: will return TRUE if the last two
  242.                   * two consonants have a ligature
  243.                   */
  244. {
  245.     int i, form, c1, c2, c2only, found, nolig;
  246.     comp_unit_t *clist, *lcus;
  247.     comp_unit_t *cimp;
  248.     dchar_t  dc, *next;
  249.  
  250.     *cus = NULL;
  251.     *imp = NULL;;
  252.     *lastlig = FALSE;
  253.     c2only = FALSE; /* flag is used for CONSDOUBLE/CONSMANY forms.
  254.              * If the ligature is not found, then the whole
  255.              * character is assumed to follow the form
  256.              * for the c2 consonant.
  257.              * BUT, that implies that the clist for c2
  258.              * contains a reference to the "implicit" char,
  259.              * so that c1-half-form also gets printed
  260.              * (by a recursive call).
  261.              * If c2 does not contain a reference to an
  262.              * implicit char, then one is stuffed in.
  263.              */
  264.  
  265.     form = dlet.v;
  266.     if (form != HALF_FORM && form != IMPLICIT_FORM) form = _I_(form);
  267.     c1 = _I_(dlet.cons[0]);
  268.     c2 = _I_(dlet.cons[1]);
  269.     nolig = dlet.nolig[0]; /* if TRUE, then do not use ligature */
  270.     dc.cus = NULL;
  271.     dc.same_as = NULL;
  272.     clist = NULL;
  273.     cimp = NULL;
  274.  
  275. #ifdef DEBUG
  276. fprintf(stderr, "get ccus form for: c1 %d, c2 %d, form %d type %d\n", c1, c2, form, dlet.type);
  277. #endif /*DEBUG*/
  278.  
  279.     switch (dlet.type) {
  280.     case CONSONANT_SINGLE_TYPE:
  281.     dc = fptr->khadi[c1];
  282.     if (dc.cus) {
  283.         clist = dc.cus[form];
  284.         cimp = dc.cus[IMPLICIT_FORM];
  285. #ifdef DEBUG
  286. fprintf(stderr, "conssingle: clist is %d cimp %d\n", (int)clist, (int)cimp);
  287. #endif /*DEBUG*/
  288.     }
  289.     break;
  290.     case CONSONANT_DOUBLE_TYPE:
  291.     *lastform = IMPLICIT_FORM;
  292.     if (!nolig) {
  293.         dc = fptr->ligatures[c1][c2];
  294.         if (dc.cus) {
  295.         *lastlig = TRUE;
  296.             clist = dc.cus[form];
  297.             cimp = dc.cus[IMPLICIT_FORM];
  298.         }
  299.     }
  300.     /* If clist is NULL, and same_as is NULL,
  301.      * consider the last consonant, and follow the form for
  302.      * its CONS..SINGLE form
  303.      * NOTE: cimp cannot be looked for!
  304.      */
  305. #ifdef DEBUG
  306. fprintf(stderr, "consdouble: before same_as clist is %d cimp %d (sameas %d)\n", (int)clist, (int)cimp, dc.same_as);
  307. #endif /*DEBUG*/
  308.     if (!clist && !dc.same_as) {
  309.         dc = fptr->khadi[c2]; /* to follow same_as ptr */
  310.         if (dc.cus) {
  311.         clist = dc.cus[form];
  312.         c2only = TRUE;
  313.         }
  314.     }
  315. #ifdef DEBUG
  316. fprintf(stderr, "consdouble: after same_as clist is %d cimp %d (new sameas %d)\n", (int)clist, (int)cimp, dc.same_as);
  317. #endif /*DEBUG*/
  318.     break;
  319.     case CONSONANT_MANY_TYPE:
  320.     *lastform = IMPLICIT_FORM;
  321.  
  322.     c1 = _I_(dlet.cons[dlet.n - 2]);
  323.     c2 = _I_(dlet.cons[dlet.n - 1]);
  324.         nolig = dlet.nolig[dlet.n-2]; /* if TRUE, then do not use ligature */
  325.  
  326.     /* if many consonants, two possibilities:
  327.      * consider the last two consonants, and follow the form for
  328.      * their ligature....
  329.      * (Note that this sometimes creates wrong characters,
  330.      * especially with the ra-cons-cons ligatures....
  331.      * (User can always prevent this by using the NOLIG_TOK - {} chars
  332.      * in the input
  333.      */
  334.     if (!nolig) {
  335.         dc = fptr->ligatures[c1][c2];
  336.         if (dc.cus)  {
  337.         clist = dc.cus[form];
  338.         *lastlig = TRUE;
  339.         }
  340. #ifdef DEBUG
  341. fprintf(stderr, "consmany: before same_as clist is %d cimp %d (sameas %d)\n", (int)clist, (int)cimp, dc.same_as);
  342. #endif
  343.     }
  344.  
  345.     if (nolig || (!clist && !dc.same_as)) {
  346.         /* if user has prohibited the ligature from
  347.          * being used, or if no ligature was found....
  348.              * consider the last consonant, and follow the form for
  349.           * its CONS..SINGLE form
  350.     Following this path also creates funny <cons>....<cons>ra-<cons>
  351.     sequences, i.e, the ra-<consonant> at the end of a letter
  352.     screws up things since in hindi mode the ra-<consonant> uses
  353.     some funky char lists .. (see dvnc.ifm, dvng.ifm)
  354.     BUT the damage here is preferable to be one if the ligature is used..
  355.      */
  356.      
  357.         dc = fptr->khadi[c2];
  358.         if (dc.cus) clist = dc.cus[form];
  359.         c2only = TRUE;
  360.      }
  361. #ifdef DEBUG
  362. fprintf(stderr, "consmany: clist is %d cimp %d sameas %d c1 %d\n", (int)clist, (int)cimp, dc.same_as, c1);
  363. #endif /*DEBUG*/
  364.  
  365.     break;
  366.     case VOWEL_TYPE:
  367.     dc = fptr->khadi[form];
  368.     form = A_FORM;
  369.     if (dc.cus) {
  370.         clist = dc.cus[form];
  371.         cimp = dc.cus[IMPLICIT_FORM];
  372.     }
  373.     break;
  374.     case SPECIAL_TYPE:
  375.     dc = fptr->khadi[c1];
  376.     form = IMPLICIT_FORM;
  377.     if (dc.cus) {
  378.         clist = dc.cus[form];
  379.         cimp = dc.cus[IMPLICIT_FORM];
  380.     }
  381.     break;
  382.     } /* switch */
  383.  
  384.     if (clist && c2only) {
  385.        /* this clist has been obtained from the c2 consonant.
  386.     * Since c1 is omitted here, make sure that clist contains
  387.     * a reference to "implicit", that way make_letter will
  388.     * add in the chars for c1 too.
  389.     */
  390.     lcus = clist;
  391.     found = FALSE;
  392.     while (lcus) {
  393.         if (lcus->u_pschar == IMPLICIT_PSCHAR) found = TRUE;
  394.         lcus = lcus->next;
  395.     }
  396.     if (!found) {
  397.         *lastform = dlet.v;
  398.         clist = &S_implicit_cu;
  399.     }
  400.     }
  401.  
  402.     /* follow the same_as pointers until get required clist */
  403.     next = dc.same_as;
  404.     while (!clist && next) {
  405.     if (next->cus)  clist = next->cus[form];
  406. #ifdef DEBUG
  407. fprintf(stderr, "getcons: following sam_as pointer clist is %d\n", (int)clist);
  408. #endif /*DEBUG*/
  409.     next = next->same_as;
  410.     }
  411.  
  412.     if (!clist) {
  413.     fprintf(stderr, "*** Error (line %d): comp_units missing (in %s) for this letter:\n",
  414.             G_lineno, fptr->fname);
  415.     for (i = 0;  i < dlet.n; i ++) {
  416.         form = dlet.cons[i];
  417.         fprintf(stderr, "*** Consonant %d: token (%d), IFM name (%s)\n",
  418.             i,form,G_ifm_map[form-A_TOK].codename);
  419.     }
  420.     if (dlet.v < A_TOK)
  421.         fprintf(stderr, "*** Vowel: token (%d), IFM name (%s)\n",
  422.                 dlet.v+OFFSET_TOK, G_ifm_map[dlet.v].codename);
  423.     else
  424.         fprintf(stderr, "*** Vowel: token (%d), IFM name (%s)\n", dlet.v,
  425.                     G_ifm_map[dlet.v-A_TOK].codename);
  426.     fprintf(stderr, "***\n");
  427.         return FALSE;
  428.     }
  429.  
  430.     *cus = clist;
  431.     *imp = cimp;
  432.     return TRUE;
  433.  
  434. } /* S_get_cus_form() */
  435. /* =================================================================== */
  436. static int S_add_cus(pschar_t psfm[], comp_unit_t* pcu, comp_unit_t cu)
  437. {
  438.     int n, w;
  439.  
  440.     *pcu = cu;
  441.     n = 1;
  442.  
  443.     /* XXX need to track bounding boxes etc */
  444.     /* if this is a zero with char, add one more comp unit */
  445.     if (cu.u_pschar >= 0 && cu.u_pschar <= 255) {
  446.     w = psfm[cu.u_pschar].w;
  447.     if (w == 0) { /* reapply delta to get back at current pos*/
  448.         pcu++;
  449.         pcu->deltax = -cu.deltax;
  450.         /* pcu->deltay = -cu.deltay; */
  451.         pcu->deltay = 0; /* no Y delta, since Y movements are always
  452.                   * restored back to correct Y value
  453.                   * by the cus_to_tex() and cus_to_ps()
  454.                   * functions...
  455.                   */
  456.         pcu->u_pschar = NO_PSCHAR; /* just delta */
  457.         n++;
  458.     }
  459.     }
  460.  
  461.     return n;
  462. }
  463. /* ============================^ dchar.c ^ =========================== */
  464.